home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_100 / 130_01 / ry.use < prev    next >
Text File  |  1985-03-09  |  10KB  |  213 lines

  1.     Ry.use, a tutorial on the use of the random file code.
  2.  
  3.     Ry.c consists of a set of functions that allow direct random access of
  4. a disk file.  This access is on a byte addressable level, using 'long integers'
  5. as provided in BDS C by the long.c functions.  The base functions are 'rgetc()'
  6. and 'rputc()'.  All other character handling functions (i.e. 'rprintf()') are
  7. built upon these two.  For details of calling conventions, etc. refer to the
  8. file 'ry.doc'.  One inportant detail, this code requires a z-80 processor to
  9. run.
  10.  
  11.     Internally, a file created by the ry code ('rcreat()') is identical to
  12. any other cp/m text file with one exception.  The first sector (known as sector
  13. '0' to cp/m) is reserved as a file header for use by 'rcreat()', 'ropen()',
  14. etc.  As such, the 'first' byte of a file comes from and goes to the first byte
  15. of sector 1.  This offset is maintained throught the file.  This is only
  16. important, however, if you use other tools (such as ddt) to diddle with a
  17. random file.  Requests to seek any byte automatically add this offset to the
  18. argument.  Using the cpm command 'type' will also cause some interesting
  19. results since the header (sector 0) will typically contain integer values that
  20. will send the console into a fit.  And if a 0x1a (^z) exists anywhere in the
  21. header you will never even see the file proper.  This inconvenience is
  22. justified in most cases by the added power that this header allows when
  23. handeling files in a random fashion.
  24.  
  25.     The first half of this header, i.e. 64 bytes, is reserved for use by
  26. 'rcreat()', 'ropen()', and 'rclose()'.  The first 4 bytes are for a long
  27. integer pointer to the EOF.  The ry code presently DOES NOT AUTOMATICALLY place
  28. this value for you.  It is the programmers responsibility to do so, if this
  29. information is needed for the next time that the file is used.  Future versions
  30. will take care of this also.  Bytes 5-8 are reserved for a timestamp of the
  31. date of file creation, bytes 9-12 for a timestamp of the date of last access.
  32. Again, these fields are not yet filled by the present version of ry code.  The
  33. remaining bytes of the first half are as yet undefined but reserved.
  34.  
  35.     The second half of the header is for use by the programmer in any way
  36. that he/she wishes.  Typically it might contain links to other files, or
  37. perhaps pointers used to separate different logical parts of a file.
  38.  
  39.     When a file is opened via 'ropen()' or 'rcreat()' the function call
  40. returns a pointer to a structure of type _file.  This pointer is used by all
  41. random function calls to refer to the file.  In 'ry.h' a #define equates the
  42. string "RFILE" to "struct _file", thus you declare a variable to hold the
  43. returned value of 'ropen()' or 'rcreat()' as RFILE *<variable_name>.  What you
  44. are doing is declaring the variable to be a pointer to an 'RFILE' or 'struct of
  45. type _file'.
  46.  
  47.     As an example, let's create a file to hold to hold a list of names.
  48. First we declare the variable used to hold the file pointer as:
  49.  
  50.     RFILE *foo;
  51.  
  52.     Next we creat the file:
  53.  
  54.     foo = rcreat("a:namefile", 'd', 8);
  55.  
  56.     The first arg is obvious, the name of the file we wish to create.  The
  57. second arg is a char that defines the mode in which we want the file to be
  58. created/opened.  In this case we used a 'd' to ask that the file be opened for
  59. 'direct' (read and write) access.  Other modes include 'r' for read only and
  60. 'w' for write only. The unix file mode 'a' (append) is not implimented yet.
  61. The third arg is the number of sectors that you want the system to use for
  62. buffering the file.  A large number here speeds things up by cutting down on
  63. the number of disk accesses, but at the cost of using a large amount of memory.
  64. Remember that this number refers to logical cp/m sectors, size of 128 bytes.
  65. In this example I used 8 so that exactly 1 physical sector (my bios uses 1k
  66. sectors) would be buffered, thus optimizing disk reads.
  67.  
  68.     The syntax is identical for 'ropen()'.  A file may be opened with a
  69. different declared access mode and buffersize than that used when it was
  70. created.  The file pointer (foo in this case) is used as an arg for all other
  71. references to this file.  It is the sole arg to 'rclose()'.  Be sure to check
  72. the file pointer for a value of ERROR (-1) when opening or creating a file.  If
  73. an ERROR is returned DO NOT 'rclose()' the file, this will bash the system!
  74. This is because of the fact that 'rclose()' returns bufferspace to the dynamic
  75. memory pool maintained by 'alloc()' and 'free()'.  This brings up one more
  76. important point, BE SURE TO HAVE THE STATEMENT '_allocp = NULL;' as the first
  77. item of any program using ry functions.  This also means that alloc() and
  78. free() must be enabled in your std libraries.
  79.  
  80.     Next, let's add a couple names to the file:
  81.  
  82.     rputs("freddy fudd", foo);
  83.     rputs("sally sue", foo);
  84.  
  85.     Here the first arg is the string that we want to put in the file, and
  86. the second is the file pointer.  Ry.doc gives details for the use of other
  87. calls such as 'rputl()' and 'rprintf()'.  All of the commands for getting
  88. things back out are also documented there.
  89.  
  90.     To retrieve the names we first have to get back to the begginning of
  91. the file:
  92.  
  93.     lseek(foo, "0", 3);
  94.  
  95.     The first arg is obviously the file pointer.  The second is the byte we
  96. want, expressed as an ascii string.  The third arg tells 'lseek()' that the
  97. second arg is a pointer to an ascii representation of the sought after byte.
  98.  
  99. The possible values for the third arg are:
  100.  
  101.     a: 0, (used above) meaning that the second arg is the address of a 4
  102. byte array holding a 'long int', the value of which is the address of the byte
  103. we want to access.  This address is relative to the first byte of the file.
  104.  
  105.     b: 1, as in 0 above, the second arg is an array holding a 'long int',
  106. but this time the address it represents is relative to the present location in
  107. the file.
  108.  
  109.     c: 2 is reserved for 'relative to end of file', not implimented yet.
  110.  
  111.     d: 3 means that the second arg is the address of an array holding an
  112. ascii representation of the byte address we want to access.  'lseek()' converts
  113. this string into the appropriate value before seeking the byte address.
  114.  
  115.     e: 4, same as 3, but address is relative to present location in file
  116. (as in 1).
  117.  
  118.     f: 5, reserved for 'ascii relative from end of file', not implimented
  119. yet. 
  120.  
  121.     Now that we have sought byte 0 from beginning of file we can reread it.
  122.  
  123.     char firstname[30], secondname[30]; /* declare strings to hold names */
  124.  
  125.     rgets(firstname, foo);
  126.     rgets(secondname, foo);
  127.  
  128.     The first arg is the destination of the string, the second the file
  129. pointer.
  130.  
  131.     Next we might want to mark the EOF:
  132.  
  133.     rputc(0x1a, foo);
  134.  
  135.     This just placed a control z in the file, following the NULL byte that
  136. terminated the string "sally sue".
  137.  
  138.     Next we want to back up 1 byte so that we are at the '^z':
  139.  
  140.     lseek(foo, "-1", 3)
  141.  
  142.     We asked to go back 1 byte from the present file location.  We are now
  143. in the file at the position of the '^z' byte following the string "sally sue".
  144. We could record this position in the file header by:
  145.  
  146.     ltell(foo, foo + 1);
  147.  
  148.     The first arg is the file pointer, the second is the address of a 4
  149. byte array that we want a 'long int' to be placed.  This 'long int' is the
  150. address of the current position in the file.  When a file is opened the header
  151. kept in sector 0  is placed in the buffer, between the struct that describes
  152. the file and the buffered file data. The first four bytes of this header are
  153. reserved for the EOF address, thus we ask 'ltell()' to place the current file
  154. position (1 byte beyond the ^z) into the first 4 bytes following the struct
  155. pointed at by foo.  Remember that foo is a pointer to a struct of type _file,
  156. thus 'foo + 1' evaluates to the address following the struct, not 1 byte beyond
  157. the beginning of foo!  Note that there is no way to make 'ltell()' return an
  158. ascii form of the address.  You would have to use 'ltoa()' to make this
  159. conversion if needed.
  160.  
  161.     Now to close the file:
  162.  
  163.     rclose(foo);
  164.  
  165.     This causes the buffer to be flushed to the disk if necessary and the
  166. header to be updated to disk.  Thus the addres